package plantshop.tests;

import static org.junit.Assert.*;

import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import plantshop.model.Characteristics;
import plantshop.model.CollisionDetector;
import plantshop.model.Creature;
import plantshop.model.Customer;
import plantshop.model.Game;
import plantshop.model.Store;
import plantshop.model.plants.Aster;
import plantshop.model.plants.BurningBush;
import plantshop.model.plants.JapaneseBarberry;
import plantshop.model.plants.NorwayMaple;
import plantshop.model.plants.Plant;
import plantshop.model.plants.SweetPepperbush;
import plantshop.model.plants.WhiteOak;
import plantshop.view.View;

public class GameTest {
	Game game;
	Store store;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
		game = new Game(View.xscale,View.yscale);
		store = game.getStore();
		CollisionDetector.setStore(store);
	}

	@After
	public void tearDown() throws Exception {
		game = null;
		store = null;
	}

	@Test
	public void testMovePlant() {
		Plant p = new Aster();
		store.addPlant(true, 1, 2, p);
		game.movePlant(true, 1, 2, true, 3, 1);
		assertEquals(p, store.getPlant(true, 3, 1));
	}

	@Test
	public void testBuyPlant() {
		Plant p = new WhiteOak();
		game.buyPlant(0, 4, p);
		assertEquals(100-20, store.getMoney());
		assertEquals(p, store.getBack().get(0).getPlant(4));
	}

	@Test
	public void testCreateCreature() {
		Creature c = new Creature(2);
		game.createCreature(c);
		assertEquals(c,game.getCreatures().get(0));
		assertEquals(1,game.getCreatures().size());
		
		game.createCreature(null);
		assertEquals(1,game.getCreatures().size());
	}

	@Test
	public void testSellPlant() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		store.addPlant(true, 0, 1, p1);
		store.addPlant(true, 1, 3, p2);
		store.addPlant(true, 1, 0, p3);
		assertEquals(100,store.getMoney());
		assertEquals(0, store.getSales());
		assertEquals(675,store.getAttractiveness());
		
		game.sellPlant(1,7);
		assertEquals(100,store.getMoney());
		assertEquals(0,store.getSales());
		assertEquals(675,store.getAttractiveness());
		
		game.sellPlant(0, 1);
		assertEquals(120,store.getMoney());
		assertEquals(1,store.getSales());
		assertEquals(637,store.getAttractiveness());
		
		game.sellPlant(-1, 0);
		
		game.sellPlant(1, 0);
		assertEquals(155,store.getMoney());
		assertEquals(2,store.getSales());
		assertEquals(749,store.getAttractiveness());
	}

	@Test
	public void testSellRequestedPlant() {
		Customer c = Customer.makeCustomer(1,new Characteristics(new int[]{5,5,10,5,5}));
		store.addCustomer(c);
		
		Plant p1 = new NorwayMaple();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		store.addPlant(true, 0, 1, p1);
		store.addPlant(true, 1, 3, p2);
		store.addPlant(true, 1, 0, p3);
		store.addPlant(false, 0, 3, p4);
		store.addPlant(true, 0, 2, p4);
		store.addPlant(false, 0, 0, p2);
		store.addPlant(false, 0, 1, p3);
		store.addPlant(false, 0, 5, p1);
		
		game.sellRequestedPlant(false, 0, 7, c.getDesiredPlant().getDominant(), c);
		assertEquals(100,store.getMoney());
		assertEquals(0,store.getSales());
		assertEquals(700,store.getAttractiveness());
		
		game.sellRequestedPlant(false, 0, 3, c.getDesiredPlant().getDominant(), c);
		assertEquals(150,store.getMoney());
		assertEquals(1,store.getSales());
		assertEquals(675,store.getAttractiveness());
		
		game.sellRequestedPlant(true, 1, 3, c.getDesiredPlant().getDominant(), c);
		assertEquals(350,store.getMoney());
		assertEquals(2,store.getSales());
		assertEquals(900,store.getAttractiveness());
		
		game.sellRequestedPlant(true, 1, 0, c.getDesiredPlant().getDominant(), c);
		assertEquals(455,store.getMoney());
		assertEquals(3,store.getSales());
		assertEquals(1125,store.getAttractiveness());
		
		game.sellRequestedPlant(true, 0, 1, c.getDesiredPlant().getDominant(), c);
		assertEquals(525,store.getMoney());
		assertEquals(4,store.getSales());
		assertEquals(1075,store.getAttractiveness());
		
		game.sellRequestedPlant(true, 0, 2, c.getDesiredPlant().getDominant(), c);
		assertEquals(575,store.getMoney());
		assertEquals(5,store.getSales());
		assertEquals(1025,store.getAttractiveness());
		
		game.sellRequestedPlant(false, 0, 0, c.getDesiredPlant().getDominant(), c);
		assertEquals(775,store.getMoney());
		assertEquals(6,store.getSales());
		assertEquals(1212,store.getAttractiveness());
		
		game.sellRequestedPlant(false, 0, 1, c.getDesiredPlant().getDominant(), c);
		assertEquals(880,store.getMoney());
		assertEquals(7,store.getSales());
		assertEquals(1399,store.getAttractiveness());
		
		game.sellRequestedPlant(false, 0, 5, c.getDesiredPlant().getDominant(), c);
		assertEquals(950,store.getMoney());
		assertEquals(8,store.getSales());
		assertEquals(1374,store.getAttractiveness());
		//Bad cases
		game.sellRequestedPlant(false,-1,0,0,c);
		game.sellRequestedPlant(false, 0, -1, 0, c);
		game.sellRequestedPlant(true, 0, 5, 0, c);
		
		game.sellRequestedPlant(false, 0, 15, 0, c);
		game.sellRequestedPlant(false, 1, 0, 0, c);
	}

	@Test
	public void testMarkPlant() {
		Plant p = new Aster();
		store.addPlant(true, 0, 2, p);
		game.markPlant(0, 3);
		assertTrue(store.getFront().get(0).getPlant(2).getAvailable());
		game.markPlant(0, 2);
		assertFalse(store.getFront().get(0).getPlant(2).getAvailable());
		game.markPlant(400, -30);
		game.markPlant(0, -30);
	}

	@Test
	public void testSendCustomer() {
		store.increaseAttractiveness(100);
		game.updateTotalScore(100);
		game.sendCustomer();
		assertEquals(1, game.getCustomers().size());
		game.sendCustomer();
		assertEquals(1, game.getCustomers().size());
		
		game.updateTotalScore(1500);
		//Now there should only be a 1 in 3 chance of getting a customer
		game.sendCustomer();
		game.sendCustomer();
		game.sendCustomer();
		assertTrue(game.getCustomers().size() <= 3);
	}

	@Test
	public void testSendCustomerCustomer() {
		game.sendCustomer(Customer.makeCustomer());
		assertEquals(1, game.getCustomers().size());
		game.sendCustomer(Customer.makeCustomer());
	}

	@Test
	public void testGetCustomers() {
		Customer c1 = Customer.makeCustomer();
		Customer c2 = Customer.makeCustomer();
		store.addCustomer(c1);
		store.addCustomer(c2);
		
		List<Customer> c = game.getCustomers();
		assertTrue(c.contains(c1));
		assertTrue(c.contains(c2));
		
		Customer c3 = Customer.makeCustomer();
		c.add(c3);
		assertFalse(game.getCustomers().contains(c3));
	}

	@Test
	public void testGetCreatures() {
		Creature c1 = new Creature(1);
		Creature c2 = new Creature(2);
		game.createCreature(c1);
		game.createCreature(c2);
		
		List<Creature> c = game.getCreatures();
		assertTrue(c.contains(c1));
		assertTrue(c.contains(c2));
		
		Creature c3 = new Creature(1);
		c.add(c3);
		assertFalse(game.getCreatures().contains(c3));
	}

	@Test
	public void testDeleteCustomer() {
		Customer c1 = Customer.makeCustomer(), c2 = Customer.makeCustomer();
		store.addCustomer(c1);
		store.addCustomer(c2);
		assertTrue(game.getCustomers().contains(c1));
		assertTrue(game.getCustomers().contains(c2));
		game.deleteCustomer(null);
		assertTrue(game.getCustomers().contains(c1));
		assertTrue(game.getCustomers().contains(c2));
		game.deleteCustomer(c1);
		assertFalse(game.getCustomers().contains(c1));
		assertTrue(game.getCustomers().contains(c2));
		assertEquals(1,game.getCustomers().size());
		game.deleteCustomer(Customer.makeCustomer());
		assertTrue(game.getCustomers().contains(c2));
	}

	@Test
	public void testDeleteCreature() {
		Creature c = new Creature(1);
		game.createCreature(c);
		assertTrue(game.getCreatures().contains(c));
		game.deleteCreature(null);
		assertTrue(game.getCreatures().contains(c));
		game.deleteCreature(c);
		assertFalse(game.getCreatures().contains(c));
	}

	@Test
	public void testDeletePlant() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		store.addPlant(true, 0, 1, p1);
		store.addPlant(true, 1, 3, p2);
		store.addPlant(true, 1, 0, p3);
		store.addPlant(false, 0, 3, p4);
		store.addPlant(true, 0, 2, p2);
		assertEquals(2,store.getCounts().get(p2).intValue());
		
		
		game.deletePlant(false, 0, 5);
		assertEquals(735,store.getAttractiveness());
		assertEquals(1,store.getBack().get(0).getPlantCounts().get(p4).intValue());
		
		game.deletePlant(true, 0, 1);
		assertEquals(710,store.getAttractiveness());
		assertFalse(store.getFront().get(0).getPlantCounts().keySet().contains(p1));
		
		game.deletePlant(true, 0, 2);
		assertEquals(650,store.getAttractiveness());
		assertEquals(1,store.getCounts().get(p2).intValue());
	}

	@Test
	public void testStartGame() {
		assertEquals(false, game.isRunning());
		game.startGame();
		assertEquals(119000, game.getGameTime());
		assertEquals(true, game.isRunning());
	}

	@Test
	public void testIsRunning() {
		assertEquals(false, game.isRunning());
		game.startGame();
		assertEquals(true, game.isRunning());
	}

	@Test
	public void testEndGame() {
		assertEquals(false, game.isRunning());
		game.startGame();
		assertEquals(true, game.isRunning());
		game.endGame();
		assertEquals(false, game.isRunning());
	}

	@Test
	public void testGetGameTime() {
		game.startGame();
		assertEquals(119000, game.getGameTime());
	}

	@Test
	public void testSetGameTime() {
		game.setGameTime(1L);
		assertEquals(1, game.getGameTime());
	}

	@Test
	public void testAddOpponent() {
		assertEquals(1, game.getNumOpponents());
		game.addOpponent();
		assertEquals(2, game.getNumOpponents());
	}
}
